﻿using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

namespace MassiveBattle
{
	public class ESide
	{
		private static readonly List<ESide> list = new List<ESide>();

		private int value;

		public static ESide PLAYER { get; private set; }
		public static ESide ENEMY { get; private set; }
		public static int END
		{
			get
			{
				return list.Count;
			}
		}

		static ESide()
		{
			PLAYER = new ESide();
			ENEMY = new ESide();
		}

		private ESide()
		{
			value = END;

			list.Add(this);
		}

#if UNITY_EDITOR
		public override string ToString()
		{
			var type = GetType();
			var propertyList = type.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
			var property = propertyList.FirstOrDefault(data => data.GetValue(null, null) == this);

			return property == null ? "not defined" : property.Name;
		}
#endif

		public static implicit operator int(ESide source)
		{
			return source.value;
		}

		public static implicit operator ESide(int source)
		{
			return list[source];
		}
	}

	public enum ELine
	{
		FIRST,
		SECOND,
		THIRD,
		END,
	}

	public enum ETactics
	{
		NONE,
		HEAL,
		DEFENCE,
		ATTACK,
	}

	public enum EArea
	{
		NONE,
		LEFT,
		MIDDLE,
		RIGHT,
	}

	public enum EState
	{
		NONE,
		STUN,
	}

	public enum EMassTake
	{
		idle01 = 0,
		die01,
		forward01,
		attack01,
		skill01,
		down01,
		damage01,
		enterstage01,
		idle02,
		Max,
	}

	public enum EStateMain
	{
		idle,
		enterstage,
		die,
		attack,
		heal,
		skill,
		forward,
	}

	public static class Query
	{
		public static IEnumerable<Controller.BaseController> GetWhere(this IEnumerable<Controller.BaseController> list, Func<Controller.BaseController, bool> func)
		{
			return list.Where(func);
		}

		public static IEnumerable<Controller.BaseController> GetOrderBy<T>(this IEnumerable<Controller.BaseController> list, Func<Controller.BaseController, T> func)
		{
			return list.OrderBy(func);
		}

		public static IEnumerable<Controller.BaseController> GetTake(this IEnumerable<Controller.BaseController> list, int count, ECount type)
		{
			if (count >= 0)
			{
				if (type == ECount.NONE)
					return list.Take(count);
				else if (type == ECount.TAUNT)
				{
					var candidateList = list.ToList();

					// 존재감 보정치(AP) = 1.15
					// 캐릭터 별 존재감 = 존재감 ^ 존재감 보정치
					// 선택 확률 = 캐릭터 별 존재감 / 전위 캐릭터 별 존재감의 합
					var tauntList = candidateList.Select(data => Mathf.Pow(data.Stat.taunt.Get(data.Manager.Monitor), 1.15f)).ToList();

					var resultList = new List<Controller.BaseController>();

					for (int i = 0; i < count; i++)
					{
						if (candidateList.Count <= 0)
							break;

						int index = candidateList.Count == 1 ? 0 : Utility.SelectRandomIndex(tauntList);

						if (index == -1)
							break;

						resultList.Add(candidateList[index]);

						candidateList.RemoveAt(index);
						tauntList.RemoveAt(index);
					}

					return resultList;
				}
			}

			return list;
		}

		public static IList<Controller.BaseController> GetToList(this IEnumerable<Controller.BaseController> list)
		{
			return list.ToList();
		}

		public enum ECount
		{
			NONE,
			TAUNT,
		}
	}

	namespace Manager
	{
		public interface IWorker
		{
			BaseManager Manager { get; }

			void SetManager(BaseManager manager);
		}
	}
}
